# -*- coding: utf-8 -*-

from werkzeug.utils import cached_property

from wxgame import db
from . import ts_func


class Player(db.Model):
    __tablename__ = 'player'

    wxid = db.Column(db.String(32), primary_key=True)
    nickname = db.Column(db.String(128))
    alias = db.Column(db.String(128))
    headimgurl = db.Column(db.String(256))
    wager_count = db.Column(db.Integer, default=0)
    wager_amount = db.Column(db.Integer, default=0)
    earned_amount = db.Column(db.Integer, default=0)
    grab_amount = db.Column(db.Integer, default=0)
    up_point = db.Column(db.Integer, default=0)
    down_point = db.Column(db.Integer, default=0)
    joined_at = db.Column(db.Integer)
    visible = db.Column(db.Integer, default=1)
    status = db.Column(db.Integer, nullable=False, default=1)
    create_time = db.Column(db.Integer, nullable=False, default=ts_func)

    rooms = db.relationship(
        'RoomPlayer',
        foreign_keys="RoomPlayer.player_wxid",
        backref=db.backref('player', lazy='joined'),
        lazy='dynamic'
    )

    invitees = db.relationship(
        'RoomPlayer',
        foreign_keys="RoomPlayer.inviter_wxid",
        backref="inviter",
    )

    # agentees = db.relationship(
    #     'RoomPlayer',
    #     foreign_keys="RoomPlayer.agent_wxid",
    #     backref="agent",
    # )

    gamesets = db.relationship(
        'PlayerGameset',
        backref=db.backref('player', lazy='joined'),
        lazy='dynamic'
    )

    transactions = db.relationship(
        'Transaction',
        backref='player',
        lazy='dynamic'
    )

    @cached_property
    def total_point(self):
        return self.earned_amount + self.up_point - self.down_point

    @cached_property
    def agent(self):
        res = AgentPlayer.query.filter_by(player_wxid=self.wxid).first()
        if res is None:
            return None
        agent = Agent.query.filter(Agent.wxid == res.agent_wxid).first()
        return agent


class PlayerGameset(db.Model):
    __tablename__ = 'player_gameset'

    id = db.Column(db.Integer, primary_key=True)
    wager_amount = db.Column(db.Integer)
    envelope_amount = db.Column(db.String(8), default='0.00')
    grab_point = db.Column(db.String(8), default='')
    grab_amount = db.Column(db.Integer, default=0)
    earned_amount = db.Column(db.Integer, default=0)
    is_banker = db.Column(db.Integer)
    status = db.Column(db.Integer, nullable=False, default=1)
    create_time = db.Column(db.Integer, nullable=False, default=ts_func)

    player_wxid = db.Column(db.String(32), db.ForeignKey('player.wxid'), nullable=True)
    gameset_id = db.Column(db.Integer, db.ForeignKey('gameset.id'), nullable=True)


class Agent(db.Model):
    __tablename__ = 'agent'

    wxid = db.Column(db.String(32), primary_key=True)
    nickname = db.Column(db.String(128))
    alias = db.Column(db.String(128))
    headimgurl = db.Column(db.String(256))
    status = db.Column(db.Integer, nullable=False, default=1)
    create_time = db.Column(db.Integer, nullable=False, default=ts_func)

    @classmethod
    def create(cls, wxid):
        agent = cls.query.filter(cls.wxid == wxid).first()
        if agent is not None:
            return False, 'Already an agent'
        player = Player.query.filter(Player.wxid == wxid).first()
        if player is None:
            return False, 'Player not exists'
        agent = cls(
            wxid=player.wxid,
            nickname=player.nickname,
            alias=player.alias,
            headimgurl=player.headimgurl
        )
        db.session.add(agent)
        try:
            db.session.commit()
        except:
            db.session.rollback()
            return False, 'DB error'
        AgentPlayer.create(wxid, wxid)
        agents = cls.query.all()
        return True, agents

    def revoke_agent(self):
        try:
            db.session.query(AgentPlayer).filter(AgentPlayer.agent_wxid == self.wxid).update(
                {'agent_wxid': None},
                synchronize_session=False
            )
            db.session.query(Agent).filter(Agent.wxid == self.wxid).delete(
                synchronize_session=False
            )
            db.session.commit()
        except:
            db.session.rollback()
            return 'DB error'

    @cached_property
    def agented_wager_amount(self):
        try:
            s = db.session.query(
                db.func.sum(Player.wager_amount)
            ).join(AgentPlayer, AgentPlayer.player_wxid == Player.wxid).filter(
                AgentPlayer.agent_wxid == self.wxid
            ).scalar()
            return int(s)
        except:
            return -1


class AgentPlayer(db.Model):
    __tablename__ = 'agent_player'

    id = db.Column(db.Integer, primary_key=True)
    agent_wxid = db.Column(db.String(32))
    player_wxid = db.Column(db.String(32), nullable=False)

    @classmethod
    def create(cls, player_wxid, agent_wxid=None):
        ap = cls.query.filter(cls.player_wxid == player_wxid).first()
        if ap is None:
            ap = cls(player_wxid=player_wxid, agent_wxid=agent_wxid)
            db.session.add(ap)
        elif ap.agent_wxid != agent_wxid:
            ap.agent_wxid = agent_wxid
        try:
            db.session.commit()
        except:
            db.session.rollback()
        return ap


class ExceptionalGrabber(db.Model):
    __tablename__ = 'exceptional_grabber'

    wxid = db.Column(db.String(32), primary_key=True)
    nickname = db.Column(db.String(128))
    alias = db.Column(db.String(128))
    headimgurl = db.Column(db.String(256))
    status = db.Column(db.Integer, nullable=False, default=1)
    create_time = db.Column(db.Integer, nullable=False, default=ts_func)

    @classmethod
    def create(cls, wxid):
        grabber = cls.query.filter(cls.wxid == wxid).first()
        if grabber is not None:
            return False, 'Already an grabber'
        player = Player.query.filter(Player.wxid == wxid).first()
        if player is None:
            return False, 'Player not exists'
        grabber = cls(
            wxid=player.wxid,
            nickname=player.nickname,
            alias=player.alias,
            headimgurl=player.headimgurl
        )
        db.session.add(grabber)
        try:
            db.session.commit()
        except:
            db.session.rollback()
            return False, 'DB error'
        return True, grabber

    def revoke_grabber(self):
        try:
            db.session.query(ExceptionalGrabber).filter(ExceptionalGrabber.wxid == self.wxid).delete(
                synchronize_session=False
            )
            db.session.commit()
        except:
            db.session.rollback()
            return 'DB error'
